Skip to content

feat(api): add canonical PolicyStatusSummary to workflow run list and describe#3061

Merged
migmartri merged 4 commits intochainloop-dev:mainfrom
migmartri:miguel/pfm-5616-policy-status-summary
Apr 21, 2026
Merged

feat(api): add canonical PolicyStatusSummary to workflow run list and describe#3061
migmartri merged 4 commits intochainloop-dev:mainfrom
migmartri:miguel/pfm-5616-policy-status-summary

Conversation

@migmartri
Copy link
Copy Markdown
Member

@migmartri migmartri commented Apr 18, 2026

Summary

Adds a canonical, server-computed PolicyStatus enum and PolicyStatusSummary (status + per-evaluation counters) to both WorkflowRunItem (list response) and AttestationItem.PolicyEvaluationStatus (describe response), so the runs list can render a policy-status badge without fanning out one View call per row. The summary is computed from a single backend helper shared by list and describe, and is materialized on the workflow_run row at attestation-ingest time to keep the list handler an index scan.

  • New flat PolicyStatus enum: NOT_APPLICABLE, PASSED, SKIPPED, WARNING, BLOCKED, BYPASSED. Enforcement (advisory vs enforced, gated, bypassed) is embedded in the enum — the raw bools remain on describe for fine-grained detail-page copy.
  • New PolicyStatusSummary { status, total, passed, skipped, violated } surfaced on both list and describe.
  • New PolicyStatusFilter on WorkflowRunService.List, aligned 1:1 with the status values. The existing PolicyViolationsFilter and the evaluations_count / violations_count fields on PolicyEvaluationStatus are preserved but marked [deprecated = true]; has_policy_violations is also preserved.
  • Five new nullable columns on workflow_run (policy_status, policy_evaluations_total, policy_evaluations_passed, policy_evaluations_skipped, policy_violations_count) plus an index on policy_status. Rows predating the change stay NULL and are interpreted as not-summarized (clients fall back to has_policy_violations).

Closes PFM-5616. Upstream prerequisite for platform spec 034 (eliminating the workflow-run describe fan-out on list views).

Test plan

  • make -C app/controlplane test-unit green (includes new 12-case table-driven test for DerivePolicyStatusSummary and extended TestPolicyEvaluationStatusCounts).
  • make -C app/controlplane test green (full integration suite including TestWorkflowRunUseCase).
  • Local push of an attestation with mixed passed/skipped/violated evaluations results in policy_summary populated on both workflow wf-run list and workflow wf-run describe.
  • Listing with the new PolicyStatusFilter returns only runs in the requested state.

… describe

Adds a canonical, server-computed PolicyStatus enum (NOT_APPLICABLE, PASSED,
SKIPPED, WARNING, BLOCKED, BYPASSED) and a PolicyStatusSummary (status +
total/passed/skipped/violated counters) to both WorkflowRunItem and
AttestationItem.PolicyEvaluationStatus. A single derivation helper feeds both
list and describe paths. The summary is materialized on the workflow_run row
at attestation-ingest time so the list handler stays an index scan. Also
introduces a PolicyStatusFilter aligned 1:1 with the enum; the coarse
PolicyViolationsFilter and the redundant evaluations_count / violations_count
fields on PolicyEvaluationStatus are marked deprecated.

Closes PFM-5616.

Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Superseded by policy_summary.status (and policy_summary.violated > 0 for the
coarse boolean case).

Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 34 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="pkg/attestation/renderer/chainloop/v02.go">

<violation number="1" location="pkg/attestation/renderer/chainloop/v02.go:487">
P2: Backfill skipped/passed counts for historic attestations before deriving the canonical status; otherwise old skipped-only envelopes are misclassified as PASSED.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread pkg/attestation/renderer/chainloop/v02.go Outdated
…ations

Attestations signed before the skipped/passed counters were added to the
predicate decode them as zero. When inline evaluations are available,
recompute at describe time so DerivePolicyStatusSummary doesn't
misclassify skipped-only runs as PASSED.

Identified by cubic.

Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Comment thread app/controlplane/api/controlplane/v1/response_messages.proto
Comment thread app/controlplane/pkg/biz/workflowrun.go
@migmartri migmartri requested a review from a team April 20, 2026 21:26
Surfaces whether a run had gates in effect (any policy marked gate:true
or contract using ENFORCED strategy) on both PolicyStatusSummary and
WorkflowRunServiceListRequest. Independent of policy status — a PASSED
run can still have has_gates=true. Materialized on workflow_run via a
partial index so the list filter is cheap.

Also refactored the renderer backfill for historic envelopes to a single
pass that derives skipped/passed counts and gate presence together.

Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 28 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="pkg/attestation/renderer/chainloop/policy_status.go">

<violation number="1" location="pkg/attestation/renderer/chainloop/policy_status.go:72">
P2: Preserve `HasGates` for zero-evaluation statuses; this early return drops the flag for enforced-but-empty runs and makes them look identical to truly ungated rows.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Passed: s.PassedCount,
Skipped: s.SkippedCount,
Violated: s.ViolationsCount,
HasGates: s.HasGates,
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Preserve HasGates for zero-evaluation statuses; this early return drops the flag for enforced-but-empty runs and makes them look identical to truly ungated rows.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At pkg/attestation/renderer/chainloop/policy_status.go, line 72:

<comment>Preserve `HasGates` for zero-evaluation statuses; this early return drops the flag for enforced-but-empty runs and makes them look identical to truly ungated rows.</comment>

<file context>
@@ -66,6 +69,7 @@ func DerivePolicyStatusSummary(s *PolicyEvaluationStatus) PolicyStatusSummary {
 		Passed:   s.PassedCount,
 		Skipped:  s.SkippedCount,
 		Violated: s.ViolationsCount,
+		HasGates: s.HasGates,
 	}
 
</file context>
Fix with Cubic

@migmartri migmartri merged commit e225955 into chainloop-dev:main Apr 21, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants